package com.safeluck.floatwindow.usbVideo;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Environment;
import android.util.Log;
import android.util.Size;
import android.view.SurfaceHolder;

import com.anyun.libusbcamera.UsbCamera;
import com.orhanobut.logger.Logger;
import com.safeluck.floatwindow.AliSdkMgr;
import com.safeluck.floatwindow.UICallBackListener;
import com.safeluck.floatwindow.app.MyApplication;
import com.safeluck.floatwindow.util.FileUtil;
import com.safeluck.floatwindow.util.MyLog;
import com.safeluck.floatwindow.util.TimeUtil;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.security.auth.login.LoginException;

/**
 * aaa
 * USBCamera本地录像
 * Created by lzw on 2018/11/14. 17:16:12
 * 邮箱：632393724@qq.com
 * All Rights Saved! Chongqing AnYun Tech co. LTD
 */
public class UsbCameraVideo {

    private static UsbCameraVideo mInstance = null;
    private UsbCamera usbCamera ;
    private boolean cameraExists;
    private static final String TAG = "UsbCameraVideo";
    private String videoPath;
    private long usbVideoStartTime;//usbCamera录像开始时间
    private long usbVideoStopTime;//usbCamera录像结束时间
    private int[] array = new int[]{640,480};
    private H264EncodeConsumer mH264Consumer;
    private AACEncodeConsumer mAacConsumer;
    private Mp4MediaMuxer mMuxer;
    private static final int USB_CAMERA_RECORD_VIDEO = 100;
    private MediaListener mMediaListener;
    private String FILE_NAME;
    private byte[] buffer;
    private boolean ay_encrypt = false;

    public String getFILE_NAME() {
        return FILE_NAME;
    }

    public static UsbCameraVideo getInstance(){
        if (mInstance == null){
            synchronized (UsbCameraVideo.class){
                if (mInstance == null){
                    mInstance = new UsbCameraVideo();
                }
            }
        }
        return mInstance;
    }

    private UsbCameraVideo(){
        usbCamera = new UsbCamera();

    }


    /**
     * 从usbCamera取数据 开始编码合成mp4视频
     * @param buffer
     */
    private void setRAWYUV(byte[] buffer){
        if (mH264Consumer!=null){
            Log.i(TAG,"setRAWYUV :"+array[0]+" height"+array[1]);
            mH264Consumer.setRawYuv(buffer,array[0],array[1]);
        }
    }

    private boolean onceStart = true;

    /**
     * 开始录制视频
     * @param params
     */
    public void startRecord(final RecordParams params){
        synchronized (UsbCameraVideo.class){

      if (onceStart){
          new Thread(){
              @Override
              public void run() {
                  super.run();
                  Logger.d( "run: USBCamera_startRecord");

                  if (params != null) {
                      videoPath = params.getRecordPath();

                      FILE_NAME = TimeUtil.video_formatTime(System.currentTimeMillis());
                      videoPath+= File.separator+FILE_NAME+".mp4";
                      MyLog.i("UsbCamera video.startRecord filename="+videoPath+"录制时间="+params.getRecordDuration());
                      if (params.getRecordDuration()==0){
                          mMuxer = new Mp4MediaMuxer(videoPath,
                                  10000  * 1000, params.isVoiceClose());
                      }else{
                          mMuxer = new Mp4MediaMuxer(videoPath,
                                  params.getRecordDuration()  * 1000, params.isVoiceClose());
                      }
//                      mMuxer = new Mp4MediaMuxer(videoPath,
//                              params.getRecordDuration() * 60 * 1000, params.isVoiceClose());
                      mMuxer.setMp4MediaMuxerLister(new Mp4MediaMuxer.Mp4MediaMuxerLister() {
                          @Override
                          public void result(int type, int errCode, String msg) {
                              Log.i(TAG, "result: "+msg);
                              if (errCode == 4){
                                  if (mMediaListener != null){
                                      mMediaListener.stop();
                                  }
                              }else if (errCode == -3){
                                  //MediaMuxer错误没有到start状态
                                  mMediaListener.ErrState(errCode);
                              }

                          }
                      });
                  }
                  if (mMediaListener != null){
                      mMediaListener.start(0,0,array[0]+","+array[1]);
                  }

                  // 启动音频编码线程
                  if (params != null && !params.isVoiceClose()) {
                      MyLog.i(TAG,"启动音频编码线程"+params.isVoiceClose());
                      startAudioRecord();
                  }
                  // 启动视频编码线程
                  startVideoRecord();
              }
          }.start();
      }
  }



}
    private void startAudioRecord() {
        mAacConsumer = new AACEncodeConsumer();

        mAacConsumer.start();
        // 添加混合器
        if (mMuxer != null) {
            if (mAacConsumer != null) {
                mAacConsumer.setTmpuMuxer(mMuxer);
            }
        }
    }

    private void startVideoRecord() {
        usbVideoStartTime = System.currentTimeMillis();
        Log.i(TAG,"H264EncodeConsumer:"+array[0]+":"+array[1]);
        mH264Consumer = new H264EncodeConsumer(array[0], array[1]);

        mH264Consumer.start();
        // 添加混合器
        if (mMuxer != null) {
            if (mH264Consumer != null) {
                mH264Consumer.setTmpuMuxer(mMuxer);
            }
        }
    }

    /**
     *
     * 停止录制
     */
    public void stopPuser(int err){
        usbVideoStopTime = System.currentTimeMillis();
        if (err == 4||err==5){

            if (mMediaListener != null){

                long dur = usbVideoStopTime-usbVideoStartTime;
                double dur_second = 1.0f*dur/1000;
                Logger.d("stopPuser: UsbCamera录像时长="+dur_second);
                mMediaListener.recordTime(videoPath,(int)dur_second,err);

            }
        }
        if (mMuxer != null){
            mMuxer.release();
            mMuxer = null;
            MyLog.i("释放音视频编码");
        }
        if (usbCamera != null){
            MyLog.i("停止本地录制后cameraExists停止usbCamera预览");
            cameraExists = false;

        }
        try {
            stopVideoRecord();
            stopAudioRecord();
        } catch (RuntimeException e) {
            MyLog.i("调用stopVideoRecord+stopAudioRecord之后发生异常，被捕捉到了~~"+e.getMessage());
            e.printStackTrace();
        }




    }
    private void stopVideoRecord() {

        if (mH264Consumer != null) {
            mH264Consumer.exit();
            mH264Consumer.setTmpuMuxer(null);
            try {
                Thread t2 = mH264Consumer;
                mH264Consumer = null;
                if (t2 != null) {
                    t2.stop();
//                    t2.join();
                }
            } catch (Exception e) {
                e.printStackTrace();
                Logger.d("stopVideoRecord exception:"+e.getMessage());
            }

        }
    }

    private void stopAudioRecord() {
        if (mAacConsumer != null) {
            mAacConsumer.exit();
            mAacConsumer.setTmpuMuxer(null);
            try {
                Thread t1 = mAacConsumer;
                mAacConsumer = null;
                if (t1 != null ) {
                    if (t1.isInterrupted())
//                    t1.interrupt();
                    t1.stop();
//                    t1.join();
                }
//            } catch (InterruptedException e) {
            } catch (Exception e) {
                e.printStackTrace();
                Logger.d("stopAudioRecord exception:"+e.getMessage());
            }



        }


    }

    /**
     * 打开相机线程
     */
   public Callable<Integer> openCallable = new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            MyLog.i(TAG, "prepareCameraWithBase 设置了分辨率"+array[0]+","+array[1]);
            int ret = usbCamera.prepareCameraWithBase( 0, 0 ,array,ay_encrypt);
            return ret;
        }
    };

    /**
     * 显示预览
     * @param surfaceHolder
     */
    public void handleStartPreview(SurfaceHolder surfaceHolder,Size size) {
        Log.i(TAG, "handleStartPreview: "+size.getWidth());
        // /dev/videox (x=cameraId + cameraBase) is used

        if (usbCamera != null){
            if (size != null){
                array[0] = size.getWidth();
                array[1] = size.getHeight();
                MyLog.i(TAG, "handleStartPreview: 设置了分辨率"+array[0]+","+array[1]);
            }else{
                MyLog.i(TAG, "handleStartPreview: 默认640*480");
                array[0] = 640;
                array[1] = 480;
            }

            ExecutorService executors = Executors.newCachedThreadPool();
            Future<Integer> openRet = executors.submit(openCallable);
            MyLog.i(TAG, "handleStartPreview: 开始打开UsbCamera");
            try {
                if (openRet.get() != -1){
                    MyLog.i("handleStartPreview: UsbCamera打开成功");
                    if (mMediaListener != null){
                        buffer = new byte[array[0]*array[1]*3/2];
                        MyLog.i("usbCamera给的分辨率"+array[0]+"x"+array[1]);
                        mMediaListener.openResult(0);
                    }
                    cameraExists = true;
                    executors.shutdownNow();//停止线程
                    new Thread(new MyPreviewRunnable(surfaceHolder)).start();

                }else{
                    MyLog.i("handleStartPreview: UsbCamera打开失败");
                    if (mMediaListener != null){

                        mMediaListener.openResult(-1);
                        mMediaListener = null;
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }

        }




    }

    public void registerMediaListener(MediaListener mediaListener){
        this.mMediaListener = mediaListener;
    }


    public interface MediaListener{
        void start(int type,int errCode,String msg);
        void stop();
        void openResult(int ret);
        void recordTime(String fileName,int sec,int err);
        void ErrState(int errcode);//也是需要停止的
    }


    /**
     * 显示预览子线程
     */
    class MyPreviewRunnable implements Runnable{
         int IMG_WIDTH = 640;
         int IMG_HEIGHT = 480;

        private int winWidth = 0;
        private int winHeight = 0;
        private Rect rect;
        private int dw, dh;
        Bitmap bitmap = Bitmap.createBitmap( array[0], array[1], Bitmap.Config.ARGB_8888 );
        private SurfaceHolder mSurfaceHodler;

        public MyPreviewRunnable(SurfaceHolder surfaceHolder) {
            MyLog.i("初始化 MyPreviewRunnable线程");
            this.mSurfaceHodler = surfaceHolder;
            Rect rect = surfaceHolder.getSurfaceFrame();
            this.winWidth = rect.right-rect.left;
            this.winHeight = rect.bottom-rect.top;
        }

        @Override
        public void run() {
            boolean reload = false;
            while (true && cameraExists) {
                // obtaining display area to draw a large image
                if (winWidth != 0) {



                    if (winWidth * 3 / 4 <= winHeight) {
                        dw = 0;
                        dh = (winHeight - winWidth * 3 / 4) / 2;
                        rect = new Rect(dw, dh, dw + winWidth - 1, dh + winWidth * 3 / 4 - 1);
                    } else {
                        dw = (winWidth - winHeight * 4 / 3) / 2;
                        dh = 0;

                        rect = new Rect(dw, dh, dw + winHeight * 4 / 3 - 1, dh + winHeight - 1);
                    }
                }

                if (reload) {
                    if (usbCamera!=null && usbCamera.prepareCameraWithBase(0, 0,array,ay_encrypt) != -1) {

                        //预览之前已经有回调摄像头分辨率了，此处不再回调
//                        if (mMediaListener != null){
//                            mMediaListener.start(0,0,array[0]+","+array[1]);
//                        }
                        reload = false;
                    }
                    if (reload){
                        MyLog.i("usbCamera!=null && usbCamera.prepareCameraWithBase(0, 0,array,ay_encrypt) == -1");
                        continue;
                    }
                }

                // obtaining a camera image (pixel data are stored in an array in JNI).
                if (usbCamera!=null && usbCamera.processCamera() == -1) {
                    MyLog.i("usbCamera!=null && usbCamera.processCamera() == -1");
                    usbCamera.stopCamera();
                    reload = true;
                    continue;
                }




                if (usbCamera != null){
                    usbCamera.pixeltobmp(bitmap);
                    usbCamera.rgba(0,buffer);
                    setRAWYUV(buffer);
                }
                Canvas canvas = mSurfaceHodler.lockCanvas();
                if (canvas != null){

                    canvas.drawBitmap(bitmap,null,rect,null);
                    mSurfaceHodler.unlockCanvasAndPost(canvas);

                }
            }
            if (usbCamera != null){
                usbCamera.stopCamera();
            }
        }
    }


}
